package com.allchips.pin.threads;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.allchips.pin.domain.OriginalStandardValue;
import com.allchips.pin.domain.PinInfoLc;
import com.allchips.pin.domain.PinInfoValue;
import com.allchips.pin.enums.DeleteFlagEnum;
import com.allchips.pin.enums.Original2StandardSyncEnum;
import com.allchips.pin.enums.PinInfoSyncEnum;
import com.allchips.pin.service.OriginalStandardValueService;
import com.allchips.pin.service.PinInfoLcService;
import com.allchips.pin.service.PinInfoValueService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import static java.lang.Math.min;

/**
 * @author gary
 * @date 2022年07月12日 11:52
 */
@Component
@Slf4j
public class Original2StandardRunning {

    @Resource
    OriginalStandardValueService originalStandardValueService;

    @Resource
    PinInfoLcService pinInfoLcService;

    @Resource
    PinInfoValueService pinInfoValueService;

    static ConcurrentHashMap<Integer, Integer> idMap = new ConcurrentHashMap<>();

    static ConcurrentHashMap<String, String> original2StandardMap = new ConcurrentHashMap<>();

    static int count = 8;


    public boolean run() {
        try {
            final int size = idMap.size();
            if (size == count) {
                return false;
            }
            LambdaQueryWrapper<OriginalStandardValue> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(OriginalStandardValue::getSync, Original2StandardSyncEnum.NO.getStatusCode());
            if (idMap.size() > 0) {
                queryWrapper.notIn(OriginalStandardValue::getId, new ArrayList<>(idMap.keySet()));
            }
            queryWrapper.eq(OriginalStandardValue::getDeleteFlag, DeleteFlagEnum.NO.getStatusCode());
            Page<OriginalStandardValue> originalStandardValuePage = originalStandardValueService.page(new Page<>(1, count - size), queryWrapper);
            if (originalStandardValuePage.getTotal() == 0) {
                return size == 0;
            }

            //查询所有替换的，缓存起来
            LambdaQueryWrapper<OriginalStandardValue> queryOriginalStandard = new LambdaQueryWrapper<>();
            queryWrapper.in(OriginalStandardValue::getSync, ListUtil.of(Original2StandardSyncEnum.NO, Original2StandardSyncEnum.YES));
            queryWrapper.eq(OriginalStandardValue::getDeleteFlag, DeleteFlagEnum.NO.getStatusCode());
            List<OriginalStandardValue> list = originalStandardValueService.list(queryOriginalStandard);
            original2StandardMap = new ConcurrentHashMap<>(list.stream().collect(Collectors.toMap(OriginalStandardValue::getOriginal, OriginalStandardValue::getStandard, (k1, k2) -> k1)));

            List<OriginalStandardValue> records = originalStandardValuePage.getRecords();
            for (OriginalStandardValue record : records) {
                Original2StandardRunning bean = SpringUtil.getBean(Original2StandardRunning.class);
                bean.dealOriginal2Standard(record);
            }
        } catch (Exception e) {
            log.error("定时同步原始值到标准值任务失败", e);
        }
        return false;
    }

    @Async
    public void dealOriginal2Standard(OriginalStandardValue record) {
        try {
            idMap.put(record.getId(), record.getId());
            //查询需要转换的数据
            List<PinInfoValue> pinInfoValueList = null;
            do {
                pinInfoValueList = pinInfoValueService.getPinIdByValue(record.getOriginal());
                if (CollUtil.isNotEmpty(pinInfoValueList)) {
                    List<Integer> pinIdList = pinInfoValueList.stream().map(PinInfoValue::getPinId).collect(Collectors.toList());

                    for (int k = 0, size = pinIdList.size(); k < size; k++) {
                        int min = min(k + 100, size);
                        final List<Integer> sub = CollUtil.sub(pinIdList, k, min);

                        //获取需要标准化的pin
                        LambdaQueryWrapper<PinInfoLc> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.select(PinInfoLc::getId, PinInfoLc::getStandardPinDt);
                        queryWrapper.in(PinInfoLc::getId, sub);
                        List<PinInfoLc> pinInfoLcList = pinInfoLcService.list(queryWrapper);

                        //需要修改的pin
                        List<PinInfoLc> updatePinInfoLc = new ArrayList<>();
                        List<PinInfoValue> savePinInfoValue = new ArrayList<>();

                        for (final PinInfoLc pinInfoLc : pinInfoLcList) {
                            final String standardPinDt = pinInfoLc.getStandardPinDt();
                            JSONObject standardPinDtObject = JSONUtil.parseObj(standardPinDt);
                            Map<String, String> tempMap = new HashMap<>();
                            Set<String> values = new HashSet<>();
                            for (final Map.Entry<String, Object> entry : standardPinDtObject.entrySet()) {
                                String value = Convert.toStr(entry.getValue());
                                String[] s = value.split(" ");
                                for (int i = 0; i < s.length; i++) {
                                    String s1 = original2StandardMap.get(s[i]);
                                    if (StrUtil.isNotBlank(s1)) {
                                        s[i] = s1;
                                    }
                                }
                                tempMap.put(entry.getKey(), ArrayUtil.join(s, " "));
                                values.addAll(Arrays.asList(s));
                            }

                            if (CollUtil.isNotEmpty(values)) {
                                for (final String value : values) {
                                    PinInfoValue pinInfoValue = new PinInfoValue();
                                    pinInfoValue.setValue(value);
                                    pinInfoValue.setPinId(pinInfoLc.getId());
                                    savePinInfoValue.add(pinInfoValue);
                                }
                            }

                            PinInfoLc update = new PinInfoLc();
                            update.setId(pinInfoLc.getId());
                            update.setStandardPinDt(JSONUtil.toJsonStr(tempMap));
                            update.setSync(PinInfoSyncEnum.STANDARD.getStatusCode());
                            update.setExceptionMsg(PinInfoSyncEnum.STANDARD.getStatusMsgEn());
                            updatePinInfoLc.add(update);
                        }

                        //删除数据
                        LambdaUpdateWrapper<PinInfoValue> updatePinInfoValue = new LambdaUpdateWrapper<>();
                        updatePinInfoValue.in(PinInfoValue::getPinId, sub);
                        pinInfoValueService.remove(updatePinInfoValue);
                        //保存value数据
                        pinInfoValueService.saveBatch(savePinInfoValue, 200);
                        //更新pin信息
                        pinInfoLcService.updateBatchById(updatePinInfoLc);

                        k = min;
                    }


                }

            } while (CollUtil.isNotEmpty(pinInfoValueList));

            //执行完，更新状态
            record.setSync(Original2StandardSyncEnum.YES.getStatusCode());
            originalStandardValueService.updateById(record);
        } catch (Exception e) {
            log.error("执行原始值转标准值异常", e);
        } finally {
            idMap.remove(record.getId());
        }
    }
}
